package com.yuandian.management.service.impl;


import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yuandian.api.management.entity.*;
import com.yuandian.api.management.enums.GraphType;
import com.yuandian.api.management.vo.EndToEndNodeVo;
import com.yuandian.api.management.vo.EndToEndRelationshipVo;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.bpm.common.security.util.SecurityUtils;
import com.yuandian.management.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * agentip管理表-Service实现
 * @author zfsn
 * @date 2023-4-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ConfEndToEndRelationshipServiceImpl implements ConfEndToEndRelationshipService {

	private final ConfGraphService confGraphService;

	private final ConfSegmentService segmentService;

	private final ConfBusinessService confBusinessService;

	private final ConfStepService confStepService;

	private final ConfNodePropertyService confNodePropertyService;

	private final ConfResourceService confResourceService;

	/**
	 * 获取步骤端到端关系
	 *
	 * @param endToEndRelationshipVo 端到端对象
	 * @return 通用返回对象
	 */
	@Override
	public List<EndToEndNodeVo> getEndToEndRelationship(EndToEndRelationshipVo endToEndRelationshipVo) {
		// 将系统id,业务编码和步骤编码 经过hash 运算生成 数值, 可以优化查询速度
		final String graphId = getGraphId(endToEndRelationshipVo);
		LambdaQueryWrapper<ConfGraph> queryWrapper = Wrappers.lambdaQuery();
		queryWrapper.eq(ConfGraph::getType, GraphType.END_AND_END_RELATIONSHIP.getType());
		queryWrapper.eq(ConfGraph::getGraphId, graphId);
		List<ConfGraph> confGraphs = confGraphService.list(queryWrapper);

		LambdaQueryWrapper<ConfNodeProperty> nodePropertyLambdaQueryWrapper = Wrappers.lambdaQuery();
		nodePropertyLambdaQueryWrapper.eq(ConfNodeProperty::getType, GraphType.END_AND_END_RELATIONSHIP.getType());
		nodePropertyLambdaQueryWrapper.eq(ConfNodeProperty::getGraphId, graphId);
		List<ConfNodeProperty> confNodeProperties = confNodePropertyService.list(nodePropertyLambdaQueryWrapper);

		// 如果步骤端到端的节点数据为空, 默认添加步骤作为作为首端
		initIfNodeIsEmpty(confNodeProperties, endToEndRelationshipVo.getStepCode(), graphId, endToEndRelationshipVo);


		if (confNodeProperties.size() != 0){
			LambdaQueryWrapper<ConfSegment> lambdaQuery = Wrappers.lambdaQuery();
			lambdaQuery.eq(ConfSegment::getSystemId, endToEndRelationshipVo.getSystemId());
//			Map<Integer, String> segmentIdAndNameMap = segmentService.list(lambdaQuery).stream().collect(Collectors.toMap(ConfSegment::getId, ConfSegment::getName));
			Map<Integer, ConfSegment> segmentIdAndNameMap = segmentService.list(lambdaQuery).stream().collect(Collectors.toMap(ConfSegment::getId, t -> t));


			List<String> nodeIds = confNodeProperties.stream().map(ConfNodeProperty::getNodeId).collect(Collectors.toList());
			Map<String, Object> nodeIdAndObjectMap = confNodeProperties.stream().collect(Collectors.toMap(ConfNodeProperty::getNodeId, k -> k, (k1, k2) -> k1));


			List<EndToEndNodeVo> endToEndNodeVos = new ArrayList<>();

			Map<String, EndToEndNodeVo> map = new HashMap<>();
			Set<String> childNodeSet = new HashSet<>();
			for (ConfGraph node : confGraphs) {
				// 找出根节点
				childNodeSet.add(node.getNodeId());
				String prev = node.getParentNodeId();
				String nodeId = node.getNodeId();
				EndToEndNodeVo treeNode = null;
				treeNode = map.getOrDefault(nodeId, getTreeNodeInfo(segmentIdAndNameMap, nodeIdAndObjectMap, nodeId));
				EndToEndNodeVo parentNode = map.getOrDefault(prev,getTreeNodeInfo(segmentIdAndNameMap, nodeIdAndObjectMap, prev));
				List<EndToEndNodeVo> childNodes = parentNode.getChildNodes();
				childNodes.add(treeNode);
				map.put(prev, parentNode);
				map.put(nodeId, treeNode);
			}
			LambdaQueryWrapper<ConfSegment> lambdaQueryWrapper = Wrappers.lambdaQuery();
			lambdaQueryWrapper.eq(ConfSegment::getSystemId, endToEndRelationshipVo.getSystemId());

			// 1 代表首端
			lambdaQueryWrapper.eq(ConfSegment::getSign, 1);
			List<ConfSegment> list = segmentService.list(lambdaQueryWrapper);
			for (String nodeId : nodeIds) {
				if(!childNodeSet.contains(nodeId)){
					EndToEndNodeVo treeNodeInfo = null;
					if (!map.containsKey(nodeId)) {
						treeNodeInfo = getTreeNodeInfo(segmentIdAndNameMap, nodeIdAndObjectMap, nodeId);
					}else {
						treeNodeInfo = map.get(nodeId);
					}
					if (list.size() > 0){
						treeNodeInfo.setSegmentId(list.get(0).getSystemId());
						treeNodeInfo.setSegmentName(list.get(0).getName());
					}
					endToEndNodeVos.add(treeNodeInfo);
				}
			}
			return endToEndNodeVos;
		}
		return null;
	}

	/**
	 * 如果步骤端到端的节点数据为空, 默认添加步骤作为作为首端
	 * @param confNodeProperties
	 * @param stepCode
	 * @param endToEndRelationshipVo
	 */
	private void initIfNodeIsEmpty(List<ConfNodeProperty> confNodeProperties, String stepCode, String graphId, EndToEndRelationshipVo endToEndRelationshipVo){
		if (confNodeProperties.size() > 0){
			return;
		}
		ConfNodeProperty confNodeProperty = new ConfNodeProperty();
		confNodeProperty.setCreateBy(SecurityUtils.getUser().getName());
		confNodeProperty.setLocationX(0D);
		confNodeProperty.setLocationY(0D);
		confNodeProperty.setType(GraphType.END_AND_END_RELATIONSHIP.getType());
		confNodeProperty.setGraphId(getGraphId(endToEndRelationshipVo));
		confNodeProperty.setNodeId(String.valueOf(IdUtil.getSnowflakeNextId()));
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("segmentId", endToEndRelationshipVo.getSegmentId());
		jsonObject.put("resourceCode", stepCode);
		jsonObject.put("systemId", endToEndRelationshipVo.getSystemId());
		jsonObject.put("businessCode", endToEndRelationshipVo.getBusinessCode());
		jsonObject.put("stepCode", endToEndRelationshipVo.getStepCode());
		jsonObject.put("isHeader", true);
		confNodeProperty.setMeta(jsonObject.toString());
		confNodePropertyService.save(confNodeProperty);
		confNodeProperties.add(confNodeProperty);
	}




	private EndToEndNodeVo getTreeNodeInfo(Map<Integer, ConfSegment> segmentIdAndNameMap, Map<String, Object> nodeIdAndObjectMap, String nodeId) {
		EndToEndNodeVo endToEndNodeVo = new EndToEndNodeVo();
		endToEndNodeVo.setNodeId(nodeId);
		endToEndNodeVo.setId(nodeId);
		if (nodeIdAndObjectMap.containsKey(nodeId)) {
			ConfNodeProperty confNodeProperty = (ConfNodeProperty) nodeIdAndObjectMap.get(nodeId);
			JSONObject jsonObject = JSONUtil.parseObj(confNodeProperty.getMeta());
			endToEndNodeVo.setLocationX(confNodeProperty.getLocationX());
			endToEndNodeVo.setLocationY(confNodeProperty.getLocationY());
			endToEndNodeVo.setResourceCode((String) jsonObject.get("resourceCode"));
			endToEndNodeVo.setSegmentId((Integer) jsonObject.get("segmentId"));
			ConfSegment confSegment = segmentIdAndNameMap.get((Integer) jsonObject.get("segmentId"));
			endToEndNodeVo.setSegmentName(confSegment != null ? confSegment.getName() : null);
			endToEndNodeVo.setSegmentInfo(confSegment);

			if (StringUtils.isNotBlank(endToEndNodeVo.getResourceCode())){
				QueryWrapper<ConfResource> queryWrapper = new QueryWrapper<>();
				queryWrapper.eq("resource_code", endToEndNodeVo.getResourceCode());
				ConfResource confResource = confResourceService.getOne(queryWrapper);
				if (confResource != null) {
					endToEndNodeVo.setIdentifyStr(confResource.getIdentifyStr());
				}

			}
		}
		return endToEndNodeVo;
	}


	/**
	 * 获取父节点和子节点的关系(一对多)
	 * @param confGraphs 图表对象
	 * @return
	 */
	@NotNull
	private Map<String, List<ConfGraph>> getParentAndChildsNodeMap(List<ConfGraph> confGraphs) {
		Map<String, List<ConfGraph>> parentAndChildsNodeMap = new HashMap<>();
		for (ConfGraph confGraph : confGraphs) {
			parentAndChildsNodeMap.computeIfAbsent(confGraph.getParentNodeId(), k -> new ArrayList<>()).add(confGraph);
		}
		return parentAndChildsNodeMap;
	}

	/**
	 * 获取关系图id
	 * @param endToEndRelationshipVo
	 * @return
	 */
	private String getGraphId(EndToEndRelationshipVo endToEndRelationshipVo) {
		return String.valueOf(HashUtil.cityHash32((endToEndRelationshipVo.getSystemId() + endToEndRelationshipVo.getBusinessCode() + endToEndRelationshipVo.getStepCode()).getBytes()));
	}

	/**
	 * 添加新节点
	 *
	 * @param endToEndRelationshipVo
	 * @return 通用返回对象
	 */
	@Override
	public String addNode(EndToEndRelationshipVo endToEndRelationshipVo) {

		String stepCode = endToEndRelationshipVo.getStepCode();
		if(ObjectUtil.isEmpty(stepCode)){
			throw new RuntimeException("步骤编码不能为空！");
		}
		String nodeId = String.valueOf(IdUtil.getSnowflakeNextId());
		//把uuid 作为节点的唯一id
		if(ObjectUtil.isNotEmpty(endToEndRelationshipVo.getNodeId())){
			nodeId = endToEndRelationshipVo.getNodeId();
		}

		// 保存节点属性信息
		ConfNodeProperty confNodeProperty = new ConfNodeProperty();
		confNodeProperty.setType(GraphType.END_AND_END_RELATIONSHIP.getType());
		confNodeProperty.setGraphId(getGraphId(endToEndRelationshipVo));
		confNodeProperty.setNodeId(nodeId);
		confNodeProperty.setLocationX(endToEndRelationshipVo.getLocationX());
		confNodeProperty.setLocationY(endToEndRelationshipVo.getLocationY());
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("segmentId", endToEndRelationshipVo.getSegmentId());
		jsonObject.put("resourceCode", endToEndRelationshipVo.getResourceCode());
		jsonObject.put("systemId", endToEndRelationshipVo.getSystemId());
		jsonObject.put("businessCode", endToEndRelationshipVo.getBusinessCode());
		jsonObject.put("stepCode", endToEndRelationshipVo.getStepCode());
		confNodeProperty.setMeta(jsonObject.toString());
		log.info("add a new node, meta is {}", jsonObject.toString());
		confNodePropertyService.save(confNodeProperty);
		ConfGraph confGraph = new ConfGraph();
		confGraph.setType(GraphType.END_AND_END_RELATIONSHIP.getType());
		confGraph.setGraphId(getGraphId(endToEndRelationshipVo));
		confGraph.setCreateBy(SecurityUtils.getUser().getName());
		confGraph.setCreateTime(LocalDateTime.now());
		confGraph.setParentNodeId(endToEndRelationshipVo.getParentNodeId());
		confGraph.setNodeId(nodeId);
		confGraphService.save(confGraph);
		return "添加新节点成功";
	}

	/**
	 * 删除节点
	 *
	 * @param endToEndRelationshipVo
	 * @return 通用返回对象
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<String> removeNode(EndToEndRelationshipVo endToEndRelationshipVo) {

		//不删除头节点
		LambdaQueryWrapper<ConfNodeProperty> lambdaQueryWrapper = Wrappers.lambdaQuery();
		lambdaQueryWrapper.eq(ConfNodeProperty::getType, GraphType.END_AND_END_RELATIONSHIP.getType());
		lambdaQueryWrapper.eq(ConfNodeProperty::getGraphId, getGraphId(endToEndRelationshipVo));
		lambdaQueryWrapper.eq(ConfNodeProperty::getNodeId, endToEndRelationshipVo.getNodeId());
		ConfNodeProperty propertyServiceOne = confNodePropertyService.getOne(lambdaQueryWrapper);
		if (propertyServiceOne == null) {
			return R.failed("该节点不存在");
		}
		JSONObject jsonObject = JSONUtil.parseObj(propertyServiceOne.getMeta());
		if (Objects.equals(jsonObject.get("isHeader"), true)) {
			return R.failed("该节点不可删除");
		}

		LambdaQueryWrapper<ConfGraph> lambdaQuery = Wrappers.lambdaQuery();
		lambdaQuery.eq(ConfGraph::getType, GraphType.END_AND_END_RELATIONSHIP.getType());
		lambdaQuery.eq(ConfGraph::getGraphId, getGraphId(endToEndRelationshipVo));
		List<String> childNodeIds = new ArrayList<>();
		if (endToEndRelationshipVo.getIsRecursiveDelete()){
			List<ConfGraph> confGraphs = confGraphService.list(lambdaQuery);
			Map<String, List<ConfGraph>> parentAndChildsNodeMap = getParentAndChildsNodeMap(confGraphs);
			getChildNodeIds(endToEndRelationshipVo.getResourceCode(), childNodeIds, parentAndChildsNodeMap);

		}
		childNodeIds.add(endToEndRelationshipVo.getNodeId());
		LambdaQueryWrapper<ConfNodeProperty> queryWrapper = Wrappers.lambdaQuery();
		queryWrapper.eq(ConfNodeProperty::getType, GraphType.END_AND_END_RELATIONSHIP.getType());
		queryWrapper.eq(ConfNodeProperty::getGraphId, getGraphId(endToEndRelationshipVo));
		queryWrapper.in(ConfNodeProperty::getNodeId, childNodeIds);
		confNodePropertyService.remove(queryWrapper);

		childNodeIds.add(endToEndRelationshipVo.getNodeId());
		lambdaQuery.in(ConfGraph::getNodeId, childNodeIds);
		 confGraphService.remove(lambdaQuery);
		return R.ok();
	}

	/**
	 * 移动节点位置
	 *
	 * @param endToEndRelationshipVo
	 * @return 通用返回对象
	 */
	@Override
	public R<String> updateNodeLocation(EndToEndRelationshipVo endToEndRelationshipVo) {
		LambdaUpdateWrapper<ConfNodeProperty> lambdaQuery = Wrappers.lambdaUpdate();
		lambdaQuery.eq(ConfNodeProperty::getType, GraphType.END_AND_END_RELATIONSHIP.getType());
		lambdaQuery.eq(ConfNodeProperty::getGraphId, getGraphId(endToEndRelationshipVo));
		lambdaQuery.eq(ConfNodeProperty::getNodeId, endToEndRelationshipVo.getNodeId());
		lambdaQuery.set(ConfNodeProperty::getLocationX, endToEndRelationshipVo.getLocationX());
		lambdaQuery.set(ConfNodeProperty::getLocationY, endToEndRelationshipVo.getLocationY());
		confNodePropertyService.update(lambdaQuery);
		return R.ok("移动节点成功");
	}

	/**
	 * 根据系统id找到所有的端到到端的关系
	 *
	 * @param systemId
	 */
	@Override
	public List<EndToEndNodeVo> getEndToEndRelationBySystemId(Integer systemId) {
		List<EndToEndNodeVo> endToEndNodeVos = new ArrayList<>();
		LambdaQueryWrapper<ConfBusiness> businessLambdaQueryWrapper = Wrappers.lambdaQuery();
		businessLambdaQueryWrapper.eq(ConfBusiness::getSystemId, systemId);
		List<ConfBusiness> confBusinesses = confBusinessService.list(businessLambdaQueryWrapper);
		for (ConfBusiness confBusiness : confBusinesses) {
			LambdaQueryWrapper<ConfStep> confStepLambdaQueryWrapper = Wrappers.lambdaQuery();
			confStepLambdaQueryWrapper.eq(ConfStep::getSystemId, systemId);
			confStepLambdaQueryWrapper.eq(ConfStep::getBusinessCode, confBusiness.getBusinessCode());
			List<ConfStep> confSteps = confStepService.list(confStepLambdaQueryWrapper);
			for (ConfStep confStep : confSteps) {
				EndToEndRelationshipVo endToEndRelationshipVo = new EndToEndRelationshipVo();
				endToEndRelationshipVo.setSystemId(systemId);
				endToEndRelationshipVo.setBusinessCode(confBusiness.getBusinessCode());
				endToEndRelationshipVo.setStepCode(confStep.getStepCode());
				endToEndNodeVos.addAll(this.getEndToEndRelationship(endToEndRelationshipVo));
			}
		}
		return endToEndNodeVos;
	}

	/**
	 * 获取字节点的nodeIds
	 * @param parentResourceCode
	 * @param childNodeIds
	 * @param parentAndChildsNodeMap
	 */
	private void getChildNodeIds(String parentResourceCode, List<String> childNodeIds, Map<String, List<ConfGraph>> parentAndChildsNodeMap){
		childNodeIds.add(parentResourceCode);
		if (parentAndChildsNodeMap.containsKey(parentResourceCode)){
			List<ConfGraph> confGraphs = parentAndChildsNodeMap.get(parentResourceCode);
			for (ConfGraph confGraph : confGraphs) {
				getChildNodeIds(confGraph.getNodeId(), childNodeIds, parentAndChildsNodeMap);
			}
		}
	}



}
